<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    body {
      padding: 100px;
    }
    #drag {
      width: 200px;
      height: 200px;
      background: #afe;
    }
    #drop {
      width: 500px;
      height: 500px;
      border: 1px solid #ccc;
    }
    #dropinner {
      margin-top: 100px;
      width: 300px;
      height: 300px;
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
<div id="drag" draggable="true">drag</div>
<div id="drop"><!--<div id="dropinner"></div>--></div>

<script>
  const $drag = document.querySelector('#drag')
  const $drop = document.querySelector('#drop')
  const $dropinner = document.querySelector('#dropinner')
  function on (dom, event, func) {
    return dom.addEventListener(event, func, false)
  }
  let $copy = null
  let position = {
    x: 0,
    y: 0,
  }

  on($drag, 'dragstart', (ev) => {
    // ev.preventDefault();
    // ev.stopPropagation();
    ev.dataTransfer.setData("data:source", JSON.stringify({ userId: 'xxx', username: 'xxx' }));
    // 深度克隆
    $copy = ev.target.cloneNode( true );
    const id = ~~(Math.random(1000) * 1000)
    $copy.setAttribute('data-id', id)
    $copy.innerHTML = $copy.innerHTML + id
    console.log('dragstart', id)
  });

  on($drop, 'dragenter', (ev) => {
    ev.preventDefault();
    ev.stopPropagation();
    if (ev.target === $copy || ev.target === $copy.parentNode ) {
      return;
    }
    position.x = ev.srcElement.offsetLeft;
    position.h = ev.srcElement.offsetHeight;
    position.y = ev.srcElement.offsetTop;
    position.w = ev.srcElement.offsetWidth;
    if ($copy.parentNode !== ev.target) {
      ev.target.appendChild($copy)
    }
  });

  function isLeaver ({ x, y }) {
    const __x = x - position.x;
    const __y = y - position.y;

    console.log('isLeaver', __x, __y, position)
    return (__x < 0 || __y < 0 || __y > position.h || __x > position.w)
  }
  on($drop, 'dragleave', (ev) => {
    ev.preventDefault();
    ev.stopPropagation();
    if (ev.target === $copy) {
      return;
    }
    if (ev.target.contains($copy) && $copy.parentNode === ev.target && isLeaver (ev)) {
      ev.target.removeChild($copy)
    }
  });
  on($drop, 'dragover', (ev) => {
    ev.preventDefault();
    ev.stopPropagation();
  });

  on($drag, 'drop', (ev) => {
    ev.preventDefault();

    console.log('drop')
    // ev.target.appendChild($copy);
    $copy = null
  });
  on($drag, 'drop', (ev) => {
    ev.preventDefault();
    ev.stopPropagation();
  });
  on($drop, 'drop', (ev) => {
    ev.preventDefault();
    ev.stopPropagation();

    console.log('drop', ev.dataTransfer.getData("data:source"))
    // ev.target.appendChild($copy);
    $copy = null
  });
</script>
</body>
</html>
